function X = slexpand(S, nums, dim)
%SLEXPAND Creates an array by repeating the source units
%
% [ Syntax ]
%   - X = slexpand(S, nums, dim)
%
% [ Arguments ]
%   - S:        The array representing the set of units to be expanded
%   - nums:     The numbers of repeated times of the units
%   - dim:      The dimension along which the units are divided and
%               expanded
%
% [ Description ]
%   - X = slexpand(S, nums, dim) divides the array S into units and creates
%     a new array by repeating each unit by the specified number of times.
%
%     For example, 
%       - X = slexpand(S, nums, 1) creates a new array by repeating each
%         row by a specified number of times. Here, nums should be a vector
%         with length equaling the number of rows in S, which specify how
%         many times each row be repeated. nums can also be a scalar, if
%         all rows are repeated by the same number of times.
%
%       - X = slexpand(S, nums, 2) creates a new array by repeating each
%         column by a specified number of times. Here, nums should be a
%         vector with length equaling the number of columns in S, or an
%         integer scalar.
%
%       - X = slexpand(S, nums, 3) creates a new array by repeating each
%         page by the specified number of times. 
%
%     The rules can be applied to higher dimensions.
%
% [ History ]
%   - Created by Dahua Lin, on Jul 9, 2007
%   - Last modified by Dahua Lin, on Dec 19, 2007
%       - implement the core index-expansion with C-mex.
%

%% parse and verify input arguments

error(nargchk(3, 3, nargin));

assert(isnumeric(nums) && isvector(nums), 'sltoolbox:slexpand:invalidarg', ...
    'The nums should be a numeric vector.');
assert(isnumeric(dim) && isscalar(dim) && dim > 0 && dim == fix(dim), ...
    'sltoolbox:slexpand:invalidarg', 'The dim should be a positive integer scalar.');

nu = size(S, dim);
assert(isscalar(nums) || length(nums) == nu, 'sltoolbox:slexpand:sizmismatch', ...
    'The length of nums should be equal to the number of units.');

%% main

if isscalar(nums)
    ns = zeros(1, nu, 'int32');
    ns(:) = int32(nums);
else
    ns = int32(nums);
end
inds = expandscalars_cimp(int32(1):int32(nu), ns);

% optimize specially for common cases
if ndims(S) == 2 && dim == 1  % repeat rows
    X = S(inds, :);
    
elseif ndims(S) == 2 && dim == 2  % repeat columns
    X = S(:, inds);
    
elseif ndims(S) <= 3 && dim == 3  % repeat pages
    X = S(:, :, inds);
    
else  % general cases
    md = max(ndims(S), dim);
    args = arrayfun(@(x) 1:size(S, x), 1:md, 'UniformOutput', false);
    args{dim} = inds;

    X = S(args{:});
end
    
    
    



